package com.hskn.hss.module.employeeTrack.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hskn.hss.entity.AjaxResult;
import com.hskn.hss.exception.HssException;
import com.hskn.hss.module.alarmcar.entity.AlarmCar;
import com.hskn.hss.module.alarmperson.entity.AlarmPerson;
import com.hskn.hss.module.alarmperson.mapper.AlarmPersonMapper;
import com.hskn.hss.module.carTrack.entity.CarTrack;
import com.hskn.hss.module.carTrack.vo.AlarmAndViolationCar;
import com.hskn.hss.module.carTrack.vo.CarTrackVo;
import com.hskn.hss.module.carTrack.vo.OrderByAlarmAndViolationCar;
import com.hskn.hss.module.carviolation.entity.CarViolation;
import com.hskn.hss.module.dlbjviolation.entity.DlbjViolation;
import com.hskn.hss.module.dlbjviolation.mapper.DlbjViolationMapper;
import com.hskn.hss.module.empPlan.entity.EmpPlan;
import com.hskn.hss.module.empPlan.mapper.EmpPlanMapper;
import com.hskn.hss.module.employeeTrack.entity.EmployeeTrack;
import com.hskn.hss.module.employeeTrack.mapper.EmployeeTrackMapper;
import com.hskn.hss.module.employeeTrack.service.EmployeeTrackService;
import com.hskn.hss.module.employeeTrack.to.EmployeeTrackTo;
import com.hskn.hss.module.employeeTrack.vo.AlarmAndViolationEmployeeVo;
import com.hskn.hss.module.employeeTrack.vo.EmployeeTrackVo;
import com.hskn.hss.module.employeeTrack.vo.OrderByAlarmAndViolationEmployeeVo;
import com.hskn.hss.module.grid.entity.Grid;
import com.hskn.hss.module.grid.mapper.GridMapper;
import com.hskn.hss.module.rptEmployeeWork.entity.RptEmployeeWork;
import com.hskn.hss.module.rptEmployeeWork.mapper.RptEmployeeWorkMapper;
import com.hskn.hss.utils.DistanceUtils;
import com.hskn.hss.utils.StringUtils;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author hskn
 * @since 2021-05-21
 */
@Service
public class EmployeeTrackServiceImpl extends ServiceImpl<EmployeeTrackMapper, EmployeeTrack> implements EmployeeTrackService {

    @Resource
    private EmployeeTrackMapper employeeTrackMapper;
    @Resource
    private GridMapper gridMapper;
    @Resource
    private AlarmPersonMapper alarmPersonMapper;
    @Resource
    private RptEmployeeWorkMapper rptCarWorkQueryWrapper;
    @Resource
    private DlbjViolationMapper dlbjViolationMapper;
    @Resource
    private RptEmployeeWorkMapper rptEmployeeWorkMapper;

    @Override
    public List mList(JSONObject params) throws HssException {

        QueryWrapper<EmployeeTrack> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().orderByAsc(EmployeeTrack::getTimestamp);
        String employeeId = params.getString("employeeId");
        if (StringUtils.isNotEmpty(employeeId)) {
            queryWrapper.lambda().eq(EmployeeTrack::getEmployeeId, employeeId);
        }
        String starttime = params.getString("starttime");
        String endtime = params.getString("endtime");
        if (StringUtils.isNotEmpty(starttime) && StringUtils.isNotEmpty(endtime)) {
            queryWrapper.lambda().between(EmployeeTrack::getTimestamp, starttime, endtime);
        }
        List<EmployeeTrack> employeeTrackList = employeeTrackMapper.selectList(queryWrapper);

        return employeeTrackList;
    }

    @Override
    public JSONObject selectPage(JSONObject params) throws HssException {

        JSONObject json = new JSONObject();
        QueryWrapper<EmployeeTrack> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().orderByAsc(EmployeeTrack::getTimestamp);
        String employeeId = params.getString("employeeId");
        if (StringUtils.isNotEmpty(employeeId)) {
            queryWrapper.lambda().eq(EmployeeTrack::getEmployeeId, employeeId);
        }
        String starttime = params.getString("starttime");
        String endtime = params.getString("endtime");
        if (StringUtils.isNotEmpty(starttime) && StringUtils.isNotEmpty(endtime)) {
            queryWrapper.lambda().between(EmployeeTrack::getTimestamp, starttime, endtime);
        }
        Long page = StringUtils.isEmpty(params.getLong("page")) ? 1 : params.getLong("page");
        Long size = StringUtils.isEmpty(params.getLong("size")) ? 10 : params.getLong("size");
        Page<EmployeeTrack> employeeTrackPage = new Page<>(page, size, true);
        IPage<EmployeeTrack> iPage = employeeTrackMapper.selectPage(employeeTrackPage, queryWrapper);
        json.put("total", iPage.getTotal());
        json.put("size", iPage.getSize());
        json.put("pages", iPage.getPages());
        json.put("current", iPage.getCurrent());
        json.put("list", iPage.getRecords());
        return json;
    }

    @Override
    public List getEmployeeAlarm(JSONObject params) {

        QueryWrapper<AlarmPerson> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().orderByAsc(AlarmPerson::getCreateTime);
        String employeeId = params.getString("employeeId");
        if (StringUtils.isNotEmpty(employeeId)) {
            queryWrapper.lambda().eq(AlarmPerson::getPersonId, employeeId);
        }
        String starttime = params.getString("starttime");
        String endtime = params.getString("endtime");
        if (StringUtils.isNotEmpty(starttime) && StringUtils.isNotEmpty(endtime)) {
            queryWrapper.lambda().between(AlarmPerson::getAlarmTime, starttime, endtime);
        }
        List<AlarmPerson> alarmPersonList = alarmPersonMapper.selectList(queryWrapper);
        return alarmPersonList;
    }

    @Override
    public AjaxResult insert(JSONObject params) {

        EmployeeTrack carTrack = params.getObject("data", EmployeeTrack.class);
        int i = employeeTrackMapper.insert(carTrack);
        boolean flag = i > 0 ? true : false;
        if (flag) {
            return AjaxResult.success("操作成功");
        } else {
            return AjaxResult.fail("操作失败，请稍后再试");
        }
    }

    @SneakyThrows
    @Override
    public List getEmployeeTrackGrid(JSONObject params) {

        QueryWrapper<RptEmployeeWork> rptEmployeeWorkQueryWrapper = new QueryWrapper<>();
        List<String> gridsList = new ArrayList<>();
        String employeeId = params.getString("employeeId");

        if (StringUtils.isNotEmpty(employeeId)) {
            rptEmployeeWorkQueryWrapper.lambda().eq(RptEmployeeWork::getEmployeeId, employeeId);
        }
        String startDate = params.getString("starttime");
        String endDate = params.getString("endtime");
        if (StringUtils.isNotEmpty(startDate) && StringUtils.isNotEmpty(endDate)) {
            rptEmployeeWorkQueryWrapper.lambda().between(RptEmployeeWork::getWorkDate, startDate.substring(0, 10), endDate.substring(0, 10));
        } else {
            rptEmployeeWorkQueryWrapper.lambda().eq(RptEmployeeWork::getWorkDate, DateUtil.format(new Date(), "YYYY-MM-dd"));
        }
        List<RptEmployeeWork> rptEmployeeWorkList = rptEmployeeWorkMapper.selectList(rptEmployeeWorkQueryWrapper);

        for (RptEmployeeWork rptEmployeeWork : rptEmployeeWorkList) {
            gridsList.add(rptEmployeeWork.getGridId());
        }
        List<Grid> GridList = new ArrayList<>();
        if (!gridsList.isEmpty()) {
            QueryWrapper<Grid> gridQueryWrapper = new QueryWrapper<>();
            gridQueryWrapper.lambda().in(Grid::getGridId, gridsList);
            GridList = gridMapper.selectList(gridQueryWrapper);
        }

        return GridList;
    }

    @Override
    public AlarmAndViolationEmployeeVo alarmAndViolationEmployeeList(EmployeeTrackTo employeeTrackTo) {
        //轨迹表
        QueryWrapper<EmployeeTrack> employeeTrackQueryWrapper = new QueryWrapper<>();
        employeeTrackQueryWrapper.lambda().orderByAsc(EmployeeTrack::getTimestamp);
        employeeTrackQueryWrapper.lambda().eq(EmployeeTrack::getEmployeeId, employeeTrackTo.getEmployeeId());
        employeeTrackQueryWrapper.lambda().between(EmployeeTrack::getTimestamp, employeeTrackTo.getStarttime(), employeeTrackTo.getEndtime());

        //报警表
        QueryWrapper<AlarmPerson> alarmPersonQueryWrapper = new QueryWrapper<>();
        alarmPersonQueryWrapper.lambda().orderByAsc(AlarmPerson::getAlarmTime);
        alarmPersonQueryWrapper.lambda().eq(AlarmPerson::getPersonId, employeeTrackTo.getEmployeeId());
        alarmPersonQueryWrapper.lambda().between(AlarmPerson::getAlarmTime, employeeTrackTo.getStarttime(), employeeTrackTo.getEndtime());

        //违规表
        QueryWrapper<DlbjViolation> dlbjViolationQueryWrapper = new QueryWrapper<>();
        dlbjViolationQueryWrapper.lambda().eq(DlbjViolation::getPersonId, employeeTrackTo.getEmployeeId());
        dlbjViolationQueryWrapper.lambda().between(DlbjViolation::getDate, employeeTrackTo.getStarttime(), employeeTrackTo.getEndtime());


        QueryWrapper<RptEmployeeWork> rptEmployeeWorkQueryWrapper = new QueryWrapper<>();
        rptEmployeeWorkQueryWrapper.lambda().eq(RptEmployeeWork::getEmployeeId, employeeTrackTo.getEmployeeId());
        rptEmployeeWorkQueryWrapper.lambda().between(RptEmployeeWork::getWorkDate, employeeTrackTo.getStarttime().substring(0, 10), employeeTrackTo.getEndtime().substring(0, 10));
        rptEmployeeWorkQueryWrapper.lambda().orderByAsc(RptEmployeeWork::getPlanStartTime);


        List<RptEmployeeWork> rptEmployeeWorkList = rptCarWorkQueryWrapper.selectList(rptEmployeeWorkQueryWrapper);
        List<EmployeeTrack> employeeTrackList = employeeTrackMapper.selectList(employeeTrackQueryWrapper);
        List<Grid> gridList = gridMapper.selectList(new QueryWrapper<>());
        Map<String, Grid> gridMap = gridList.stream().collect(Collectors.groupingBy(Grid::getGridId, Collectors.collectingAndThen(toList(), grids -> grids.get(0))));
        for (EmployeeTrack employeeTrack : employeeTrackList) {
            for (RptEmployeeWork rptEmployeeWork : rptEmployeeWorkList) {
                if (null != gridMap.get(rptEmployeeWork.getGridId()) &&
                        rptEmployeeWork.getPlanStartTime().compareTo(employeeTrack.getTimestamp()) >= 0
                        && employeeTrack.getTimestamp().compareTo(rptEmployeeWork.getPlanEndTime()) <= 0
                        && DistanceUtils.insideGrid(Double.parseDouble(employeeTrack.getLng()), Double.parseDouble(employeeTrack.getLat()), gridMap.get(rptEmployeeWork.getGridId()))) {
                    employeeTrack.setIsWorkIng(1);
                    break;
                } else {
                    employeeTrack.setIsWorkIng(0);
                }
            }
        }

        for (int i = 0; i < employeeTrackList.size(); i++) {
            employeeTrackList.get(i).setIndex(i);
            employeeTrackList.get(i).setIsDanger(0);
            employeeTrackList.get(i).setIsWarning(0);
            employeeTrackList.get(i).setWarningStay(0);
        }
        Map<String, EmployeeTrack> employeeTrackMap = employeeTrackList.stream().collect(Collectors.groupingBy(EmployeeTrack::getId, Collectors.collectingAndThen(toList(), employeeTracks -> employeeTracks.get(0))));

        AlarmAndViolationEmployeeVo alarmAndViolationEmployeeVo = new AlarmAndViolationEmployeeVo();

        List<OrderByAlarmAndViolationEmployeeVo> orderByAlarmAndViolationEmployeeVoLists = new ArrayList<>();
        List<OrderByAlarmAndViolationEmployeeVo> alarmCarCollectVo = new ArrayList<>();
        List<OrderByAlarmAndViolationEmployeeVo> warningStayCollectVo = new ArrayList<>();
        List<OrderByAlarmAndViolationEmployeeVo> otherWarningCollectVo = new ArrayList<>();
        List<OrderByAlarmAndViolationEmployeeVo> dlbjViolationCollectVo = new ArrayList<>();

        //报警
        List<AlarmPerson> alarmPersonList = alarmPersonMapper.selectList(alarmPersonQueryWrapper);

        alarmPersonList.forEach(alarmPerson -> {
            OrderByAlarmAndViolationEmployeeVo orderByAlarmAndViolationEmployeeVo = new OrderByAlarmAndViolationEmployeeVo();
            orderByAlarmAndViolationEmployeeVo.setId(alarmPerson.getPersonId());
            orderByAlarmAndViolationEmployeeVo.setAddress(alarmPerson.getAddress());
            orderByAlarmAndViolationEmployeeVo.setStartTime(alarmPerson.getAlarmStartTime());
            orderByAlarmAndViolationEmployeeVo.setEndTime(alarmPerson.getAlarmEndTime());
            orderByAlarmAndViolationEmployeeVo.setEmployeeName(alarmPerson.getPersonName());
            orderByAlarmAndViolationEmployeeVo.setTime(alarmPerson.getAlarmTime());
            orderByAlarmAndViolationEmployeeVo.setContent(alarmPerson.getContent());
            orderByAlarmAndViolationEmployeeVo.setTypeName(alarmPerson.getAlarmTypeName());
            orderByAlarmAndViolationEmployeeVo.setLat(alarmPerson.getLat());
            orderByAlarmAndViolationEmployeeVo.setLng(alarmPerson.getLng());
            orderByAlarmAndViolationEmployeeVo.setMessageType(1);
            List<EmployeeTrackVo> dangerList = new ArrayList<>();
            if (null != employeeTrackMap.get(alarmPerson.getEmployeeTrackStartId()) && null != employeeTrackMap.get(alarmPerson.getEmployeeTrackEndId())) {
                for (int k = employeeTrackMap.get(alarmPerson.getEmployeeTrackStartId()).getIndex(); k <= employeeTrackMap.get(alarmPerson.getEmployeeTrackEndId()).getIndex(); k++) {
                    EmployeeTrackVo employeeTrackVo = new EmployeeTrackVo();
                    employeeTrackVo.setId(employeeTrackList.get(k).getId());
                    employeeTrackVo.setAddress(employeeTrackList.get(k).getAddress());
                    employeeTrackVo.setMessage(employeeTrackList.get(k).getMessage());
                    employeeTrackVo.setLat(employeeTrackList.get(k).getLat());
                    employeeTrackVo.setLng(employeeTrackList.get(k).getLng());
                    employeeTrackVo.setMessageType(1);
                    dangerList.add(employeeTrackVo);
                }
            }
            alarmPerson.setAlarmTime(alarmPerson.getAlarmTime());
            alarmPerson.setMessageType(1);
            alarmPerson.setDangerList(dangerList);
            alarmPerson.setId(alarmPerson.getPersonId());
            orderByAlarmAndViolationEmployeeVo.setDangerList(dangerList);
            orderByAlarmAndViolationEmployeeVoLists.add(orderByAlarmAndViolationEmployeeVo);
            alarmCarCollectVo.add(orderByAlarmAndViolationEmployeeVo);
        });
        //违规
        List<DlbjViolation> dlbjViolationList = dlbjViolationMapper.selectList(dlbjViolationQueryWrapper);

        //停留的集和
        List<DlbjViolation> warningStayCollect = dlbjViolationList.stream().filter(dlbjViolation -> null != dlbjViolation.getViolationTypeName() && dlbjViolation.getViolationTypeName().equals("停留")).collect(toList());
        warningStayCollect.forEach(dlbjViolation -> {
            OrderByAlarmAndViolationEmployeeVo orderByAlarmAndViolationEmployeeVo = new OrderByAlarmAndViolationEmployeeVo();
            orderByAlarmAndViolationEmployeeVo.setId(dlbjViolation.getDlbjViolationId());
            orderByAlarmAndViolationEmployeeVo.setAddress(dlbjViolation.getAddress());
            orderByAlarmAndViolationEmployeeVo.setStartTime(dlbjViolation.getViolationStartTime());
            orderByAlarmAndViolationEmployeeVo.setEndTime(dlbjViolation.getViolationEndTime());
            orderByAlarmAndViolationEmployeeVo.setEmployeeName(dlbjViolation.getPersonName());
            orderByAlarmAndViolationEmployeeVo.setTime(dlbjViolation.getDate());
            orderByAlarmAndViolationEmployeeVo.setContent(dlbjViolation.getContent());
            orderByAlarmAndViolationEmployeeVo.setTypeName(dlbjViolation.getViolationTypeName());
            orderByAlarmAndViolationEmployeeVo.setMessageType(3);
            orderByAlarmAndViolationEmployeeVo.setLat(dlbjViolation.getLat());
            orderByAlarmAndViolationEmployeeVo.setLng(dlbjViolation.getLng());
            orderByAlarmAndViolationEmployeeVoLists.add(orderByAlarmAndViolationEmployeeVo);
            List<EmployeeTrackVo> warningStayList = new ArrayList<>();
            if (null != employeeTrackMap.get(dlbjViolation.getEmployeeTrackStartId()) && null != employeeTrackMap.get(dlbjViolation.getEmployeeTrackEndId())) {
                for (int k = employeeTrackMap.get(dlbjViolation.getEmployeeTrackStartId()).getIndex(); k <= employeeTrackMap.get(dlbjViolation.getEmployeeTrackEndId()).getIndex(); k++) {
                    EmployeeTrackVo employeeTrackVo = new EmployeeTrackVo();
                    employeeTrackVo.setId(employeeTrackList.get(k).getId());
                    employeeTrackVo.setAddress(employeeTrackList.get(k).getAddress());
                    employeeTrackVo.setMessage(employeeTrackList.get(k).getMessage());
                    employeeTrackVo.setLat(employeeTrackList.get(k).getLat());
                    employeeTrackVo.setLng(employeeTrackList.get(k).getLng());
                    employeeTrackVo.setMessageType(3);
                    warningStayList.add(employeeTrackVo);
                }
            }
            dlbjViolation.setMessageType(3);
            dlbjViolation.setId(dlbjViolation.getDlbjViolationId());
            dlbjViolation.setWarningStayList(warningStayList);
            warningStayCollectVo.add(orderByAlarmAndViolationEmployeeVo);
            dlbjViolationCollectVo.add(orderByAlarmAndViolationEmployeeVo);
        });

        List<DlbjViolation> otherWarningCollect = dlbjViolationList.stream().filter(dlbjViolation -> null != dlbjViolation.getViolationTypeName() && !dlbjViolation.getViolationTypeName().equals("停留")).collect(toList());
        otherWarningCollect.forEach(dlbjViolation -> {
            OrderByAlarmAndViolationEmployeeVo orderByAlarmAndViolationEmployeeVo = new OrderByAlarmAndViolationEmployeeVo();
            orderByAlarmAndViolationEmployeeVo.setId(dlbjViolation.getDlbjViolationId());
            orderByAlarmAndViolationEmployeeVo.setAddress(dlbjViolation.getAddress());
            orderByAlarmAndViolationEmployeeVo.setStartTime(dlbjViolation.getViolationStartTime());
            orderByAlarmAndViolationEmployeeVo.setEndTime(dlbjViolation.getViolationEndTime());
            orderByAlarmAndViolationEmployeeVo.setEmployeeName(dlbjViolation.getPersonName());
            orderByAlarmAndViolationEmployeeVo.setTime(dlbjViolation.getDate());
            orderByAlarmAndViolationEmployeeVo.setContent(dlbjViolation.getContent());
            orderByAlarmAndViolationEmployeeVo.setTypeName(dlbjViolation.getViolationTypeName());
            orderByAlarmAndViolationEmployeeVo.setMessageType(2);
            orderByAlarmAndViolationEmployeeVo.setLat(dlbjViolation.getLat());
            orderByAlarmAndViolationEmployeeVo.setLng(dlbjViolation.getLng());
            List<EmployeeTrackVo> otherWarningList = new ArrayList<>();
            if (null != employeeTrackMap.get(dlbjViolation.getEmployeeTrackStartId()) && null != employeeTrackMap.get(dlbjViolation.getEmployeeTrackEndId())) {
                for (int k = employeeTrackMap.get(dlbjViolation.getEmployeeTrackStartId()).getIndex(); k <= employeeTrackMap.get(dlbjViolation.getEmployeeTrackEndId()).getIndex(); k++) {
                    EmployeeTrackVo employeeTrackVo = new EmployeeTrackVo();
                    employeeTrackVo.setId(employeeTrackList.get(k).getId());
                    employeeTrackVo.setAddress(employeeTrackList.get(k).getAddress());
                    employeeTrackVo.setMessage(employeeTrackList.get(k).getMessage());
                    employeeTrackVo.setLat(employeeTrackList.get(k).getLat());
                    employeeTrackVo.setLng(employeeTrackList.get(k).getLng());
                    employeeTrackVo.setMessageType(2);
                    otherWarningList.add(employeeTrackVo);
                }
            }
            dlbjViolation.setMessageType(2);
            dlbjViolation.setId(dlbjViolation.getDlbjViolationId());
            dlbjViolation.setOtherWarningList(otherWarningList);
            orderByAlarmAndViolationEmployeeVo.setOtherWarningList(otherWarningList);
            orderByAlarmAndViolationEmployeeVoLists.add(orderByAlarmAndViolationEmployeeVo);
            otherWarningCollectVo.add(orderByAlarmAndViolationEmployeeVo);
            dlbjViolationCollectVo.add(orderByAlarmAndViolationEmployeeVo);
        });

        ListSort(orderByAlarmAndViolationEmployeeVoLists);
        alarmAndViolationEmployeeVo.setOrderByAlarmAndViolationEmployees(orderByAlarmAndViolationEmployeeVoLists); //合并
        ListSort(alarmCarCollectVo);
        alarmAndViolationEmployeeVo.setAlarmEmployeeList(alarmCarCollectVo);
        ListSort(warningStayCollectVo);
        alarmAndViolationEmployeeVo.setWarningStayCollect(warningStayCollectVo);
        ListSort(otherWarningCollectVo);
        alarmAndViolationEmployeeVo.setOtherWarningCollect(otherWarningCollectVo);
        alarmAndViolationEmployeeVo.setEmployeeTrackList(employeeTrackList);
        ListSort(dlbjViolationCollectVo);
        alarmAndViolationEmployeeVo.setEmployeeViolationList(dlbjViolationCollectVo);

        return alarmAndViolationEmployeeVo;
    }

    /**
     * 根据时间排序（其他排序如根据id排序也类似）
     *
     * @param orderByAlarmAndViolationEmployeeVos
     */
    private static void ListSort(List<OrderByAlarmAndViolationEmployeeVo> orderByAlarmAndViolationEmployeeVos) {
        //用Collections这个工具类传list进来排序
        Collections.sort(orderByAlarmAndViolationEmployeeVos, new Comparator<OrderByAlarmAndViolationEmployeeVo>() {
            @Override
            public int compare(OrderByAlarmAndViolationEmployeeVo o1, OrderByAlarmAndViolationEmployeeVo o2) {
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date dt1 = null;
                Date dt2 = null;
                try {
                    dt1 = format.parse(StringUtils.DateFormat(o1.getTime()));
                    dt2 = format.parse(StringUtils.DateFormat(o2.getTime()));

                } catch (Exception e) {
                    e.printStackTrace();
                }
                return dt2.compareTo(dt1);
            }
        });
    }
}
